import importlib.util
import subprocess
import sys
import socket
import struct
import select
import time
import gradio as gr

# 检查并安装缺失的库
def check_and_install(package):
    if importlib.util.find_spec(package) is None:
        print(f"正在安装 {package}...")
        subprocess.check_call([sys.executable, "-m", "pip", "install", package])
    else:
        print(f"{package} 已安装")

# 确保 gradio 已安装
check_and_install("gradio")

# 定义函数来解析域名获取所有IP地址
def get_ips_from_domain(domain):
    try:
        # 获取域名的所有IP地址
        ip_list = set()
        for addr_info in socket.getaddrinfo(domain, 80, family=socket.AF_UNSPEC, proto=socket.IPPROTO_TCP):
            ip = addr_info[4][0]
            ip_list.add(ip)
        return list(ip_list)
    except socket.gaierror as e:
        return f"无法解析域名: {domain} - {e}"

# 定义函数来发送ICMP请求并测量延迟
def ping_ip(ip, timeout=5):
    try:
        # 创建一个原始套接字
        icmp_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)
        icmp_socket.settimeout(timeout)

        # 构造ICMP包
        icmp_id = 1
        icmp_seq = 1
        checksum = 0
        header = struct.pack("!BBHHH", 8, 0, checksum, icmp_id, icmp_seq)
        data = b'P' * 32
        packet = header + data

        # 计算校验和
        checksum = in_checksum(packet)
        header = struct.pack("!BBHHH", 8, 0, checksum, icmp_id, icmp_seq)
        packet = header + data

        # 发送ICMP请求
        start_time = time.time()
        icmp_socket.sendto(packet, (ip, 0))

        # 接收ICMP响应
        ready = select.select([icmp_socket], [], [], timeout)
        if ready[0]:
            recv_packet, addr = icmp_socket.recvfrom(1024)
            end_time = time.time()
            delay = (end_time - start_time) * 1000  # 转换为毫秒
            return f"平均延迟: {delay:.2f} ms"
        else:
            return "请求超时"
    except Exception as e:
        return f"未知错误: {e}"
    finally:
        icmp_socket.close()

# 计算校验和
def in_checksum(source_string):
    sum = 0
    count_to = (len(source_string) // 2) * 2
    for i in range(0, count_to, 2):
        this_val = source_string[i+1] * 256 + source_string[i]
        sum = sum + this_val
        sum = sum & 0xffffffff  # 必要时进行截断
    if count_to < len(source_string):
        sum = sum + source_string[len(source_string) - 1]
        sum = sum & 0xffffffff  # 必要时进行截断
    sum = (sum >> 16) + (sum & 0xffff)
    sum = sum + (sum >> 16)
    answer = ~sum
    answer = answer & 0xffff
    answer = answer >> 8 | (answer << 8 & 0xff00)
    return answer

# 定义函数来处理输入的网址
def process_domain(domain):
    ip_list = get_ips_from_domain(domain)
    if isinstance(ip_list, str):  # 如果get_ips_from_domain返回了一个字符串，说明有错误
        return ip_list
    
    results = []
    for ip in ip_list:
        result = ping_ip(ip)
        results.append(f"{ip}: {result}")
    return "\n".join(results)

# 创建Gradio接口
iface = gr.Interface(
    fn=process_domain,
    inputs=gr.Textbox(placeholder="在这里输入网址..."),
    outputs="text",
    title="测试网站IP延迟",
    description="请输入你想测试的网站网址。点击提交后，你将看到该网站每个IP的延迟情况。"
)

# 启动Gradio应用
iface.launch()
